#include "tdp2_visualresources.hpp"
#include "tdp2_maincontext.hpp"
#include "../../rdx/src/rdx/rdx_objectmanagement.hpp"

namespace TDP
{
	namespace Resources
	{
		using namespace RDX::ObjectManagement;

		class VisualResourcesTypeHostDetached : public INativeTypeHost
		{
		public:
			NativeCallback HookMethod(const String *str) const;
			virtual void SetTypeProperties(IObjectManager *objm, StructuredType *st) const;
		protected:
			void SetTypePropertiesDetached(IObjectManager *objm, StructuredType *st) const;
		};
		static VisualResourcesTypeHostDetached VisualResourcesTypeHostDetached_ik;
		
		class VisualResourcesTypeHostIntegrated : public VisualResourcesTypeHostDetached
		{
		public:
			void SetTypeProperties(IObjectManager *objm, StructuredType *st) const;
		};
		static VisualResourcesTypeHostIntegrated VisualResourcesTypeHostIntegrated_ik;

		class StreamableResourceProcessor : public ITypeProcessor
		{
			void MarkDependencies(IObjectManager *objm, void *obj, const Programmability::StructuredType *st, bool markNative, ISerializer *ser, ScanID scanID, RDX::ObjectManagement::GCLink gcl) const;
			void Finalize(void *obj, IObjectManager *objm) const;
			bool OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const;
		};
		static StreamableResourceProcessor StreamableResourceProcessor_ik;
	}
}

namespace TDP
{
	namespace Resources
	{
		void StreamableResourceProcessor::MarkDependencies(IObjectManager *objm, void *obj, const Programmability::StructuredType *st, bool markNative, ISerializer *ser, ScanID scanID, RDX::ObjectManagement::GCLink gcl) const
		{
		}

		void StreamableResourceProcessor::Finalize(void *obj, IObjectManager *objm) const
		{
			StreamableResource *res = static_cast<StreamableResource *>(obj);
			MainContext::FromObjectManager(objm)->ReleaseResource(res->_native.resHandle);
			res->_native.resHandle = 0;
			MainContext::FromObjectManager(objm)->ReleaseStreamableResource(res);
		}
		
		bool StreamableResourceProcessor::OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const
		{
			const Type *objT = GCInfo::From(obj)->containerType;
			const String *gstName = GCInfo::From(objT)->gstSymbol;
			StreamableResource *res = static_cast<StreamableResource*>(obj);

			if(!gstName)
				return false;

			if(gstName->Equal("TDP.Resources.BundledGeometryData"))
				res->_native.lrhType = RT_Geometry;
			else if(gstName->Equal("TDP.Resources.BundledTexture"))
				res->_native.lrhType = RT_Texture;
			else if(gstName->Equal("TDP.Resources.BundledCompiledShader"))
				res->_native.lrhType = RT_CompiledShader;
			else if(gstName->Equal("TDP.Resources.ResourceBundle"))
			{
				// Most bundled resources don't register for stream-in immediately, but rather, stream in via the bundle.
				res->_native.lrhType = RT_Bundle;
				MainContext::FromObjectManager(objm)->RegisterStreamableResource(res);
			}
			else
				return false;

			return true;
		}

		// This only sets type sizes and doesn't set processors, so that tools can use it
		void VisualResourcesTypeHostDetached::SetTypePropertiesDetached(IObjectManager *objm, StructuredType *st) const
		{
			const String *str = GCInfo::From(st)->gstSymbol;
			if(!str)
				return;

			if(str->Equal("TDP.Resources.StreamableResource"))
			{
				st->_native.user.nativeSize = sizeof(StreamableResource::NativeProperties);
				st->_native.user.nativeAlignment = RDX_ALIGNOF(StreamableResource::NativeProperties);
				return;
			}
		}

		
		void VisualResourcesTypeHostDetached::SetTypeProperties(IObjectManager *objm, StructuredType *st) const
		{
			this->SetTypePropertiesDetached(objm, st);
		}

		NativeCallback VisualResourcesTypeHostDetached::HookMethod(const String *str) const
		{
			return NULL;
		}

		// This will call Detached sets as well as set processors
		void VisualResourcesTypeHostIntegrated::SetTypeProperties(IObjectManager *objm, StructuredType *st) const
		{
			this->SetTypePropertiesDetached(objm, st);

			const String *str = GCInfo::From(st)->gstSymbol;
			if(!str)
				return;

			if(str->Equal("TDP.Resources.StreamableResource"))
			{
				st->_native.user.typeProcessor = &StreamableResourceProcessor_ik;
				return;
			}
		}

		const INativeTypeHost *GetVisualResourcesPluginDetached()
		{
			return &VisualResourcesTypeHostDetached_ik;
		}

		const INativeTypeHost *GetVisualResourcesPluginIntegrated()
		{
			return &VisualResourcesTypeHostIntegrated_ik;
		}
	}
}